

function Map(width, height) {
  this.width = width;
  this.height = height;
  this.cells = [];
  this.panx = 0;
  this.pany = 0;
  
  this.OFFSETX = resource.grass.width * 0.75 - 1;
  this.OFFSETY = resource.grass.height - 1;
  this.PANMINX = resource.grass.width * 0.25;
  this.PANMINY = resource.grass.height * 0.5;
  this.PANBORDER = 150;
  this.PANSPEED = 50;
  
  // Layout the Maps Cells
  var i = 0;
  var cx = 0;
  var cy = 0;
  for (var y = 0; y < this.height; y++) {
    for (var x = 0; x < this.width; x++) {
      this.cells[i] = new Cell(i, cx, cy);
      i++;
      cx += this.OFFSETX;
      x++;
      if (x < this.width) {
        this.cells[i] = new Cell(i, cx, cy + this.OFFSETY * 0.5);
        i++;
        cx += this.OFFSETX;
      }
    }
    cx = 0;
    cy += this.OFFSETY;
  }  
  
  // Centre on the middle Cell by default
  this.selectedCellX = parseInt(width/2);
  this.selectedCellY = parseInt(height/2);
  this.centre(this.getCell(this.selectedCellX, this.selectedCellY));
};


/**
 * Called when mouse moves
 *
 */
Map.prototype.onmousemove = function() {
  
  // Scan the visible Cells for sending mouseover event to
  var cell = null;
  var incell = null;
  var last = this.firstcell + this.width * this.CELLSPERCOL;
  var next = this.firstcell + this.width;
  for (var i = this.firstcell; i < last; i++) {
      cell = this.cells[i];
      if (cell.contains(ooc.mousex, ooc.mousey)) {
        incell = cell;
        cell.onmouseover();
        break;
      }
      if (cell.x - this.viewx > ooc.canvas.width) {
        i = next - 1;
        next += this.width;
      }      
  }
  
  this.panx = 0;
  this.pany = 0;
  
  // Check for mouse near edge to find panning amount
  if (ooc.mousex < this.PANBORDER && ooc.mousex > 1 && this.viewx > 0)
    this.panx = -2/(ooc.mousex / this.PANBORDER);
  else if (ooc.mousex > ooc.canvas.width - this.PANBORDER && ooc.mousex < ooc.canvas.width - 1&& this.viewx < this.PANMAXX)
    this.panx = 2/((ooc.canvas.width - ooc.mousex) / this.PANBORDER);
  if (ooc.mousey < this.PANBORDER && ooc.mousey > 1 && this.viewy > 0)
    this.pany = -2/(ooc.mousey / this.PANBORDER);
  else if (ooc.mousey > ooc.canvas.height - this.PANBORDER && ooc.mousey < ooc.canvas.height - 1 && this.viewy < this.PANMAXY)
    this.pany = 2/((ooc.canvas.height - ooc.mousey) / this.PANBORDER);
    
  // Sanitise pan to whole integers and defined limits
  if (this.panx > this.PANSPEED) this.panx = this.PANSPEED;
  else if (this.panx < -this.PANSPEED) this.panx = -this.PANSPEED;
  if (this.pany > this.PANSPEED) this.pany = this.PANSPEED;
  else if (this.pany < -this.PANSPEED) this.pany = -this.PANSPEED;
  
  return incell;
};


/**
 * Called when mouse leaves the canvas
 *
 */
Map.prototype.onmouseout = function() {
  this.panx = 0;
  this.pany = 0;
};


/**
 * Called when window resized
 *
 */
Map.prototype.onresize = function() {
  this.PANMAXX = (this.width * this.OFFSETX) - ooc.canvas.width;
  if (this.PANMAXX < 0) this.PANMAXX = this.PANMINX;
  this.PANMAXY = (this.height * this.OFFSETY) - ooc.canvas.height;
  if (this.PANMAXY < 0) this.PANMAXY = this.PANMINY;
  this.sanitiseview();
};



Map.prototype.getCell = function(gridx, gridy) {
  return this.cells[gridy * this.width + gridx];
};



Map.prototype.selectCell = function(pointx, pointy) {
  for (var i = 0; i < this.cells.length; i++) {
    if (this.cells[i].contains(pointx, pointy))
      this.cells[i].select();
  }
};



/**
 * Santises the view so that you can't see past the edge cells
 *
 */
Map.prototype.sanitiseview = function() {

  if (this.viewx < this.PANMINX)
    this.viewx = this.PANMINX;
  else if (this.viewx > this.PANMAXX)
    this.viewx = this.PANMAXX;
  if (this.viewy < this.PANMINY)
    this.viewy = this.PANMINY;
  else if (this.viewy > this.PANMAXY)
    this.viewy = this.PANMAXY;
    
  this.firstcell = parseInt((this.viewy - this.OFFSETY) / this.OFFSETY) * this.width;
  this.firstcell += parseInt((this.viewx - this.OFFSETX) / this.OFFSETX);
  
  if (this.firstcell < 0)
    this.firstcell = 0;
    
  var cell = this.cells[this.firstcell];
  if (this.PANMAXX == this.PANMINX)
    this.CELLSPERROW = this.width;
  else
    this.CELLSPERROW = parseInt(ooc.canvas.width / this.OFFSETX) + 3;
  if (this.PANMAXY == this.PANMINY)
    this.CELLSPERCOL = this.height;
  else
    this.CELLSPERCOL = parseInt(ooc.canvas.height / this.OFFSETY) + 3;
  
  var cell = this.cells[this.firstcell];
  var lastcell = this.cells[this.cells.length - 1];
  if (cell.x + ((this.CELLSPERROW - 1) * this.OFFSETX) > lastcell.x + lastcell.width / 2)
    this.CELLSPERROW--;
  if (cell.y + ((this.CELLSPERCOL - 1) * this.OFFSETY) > lastcell.y + lastcell.height / 2)
    this.CELLSPERCOL--;
    
  ooc.redraw();
}


/**
 * Moves the view so that the specified cell is at the centre
 *
 */
Map.prototype.centre = function(cell) {
  this.viewx = parseInt(cell.x + (cell.width * 0.5) - (ooc.canvas.width * 0.5));
  this.viewy = parseInt(cell.y + (cell.height * 0.5) - (ooc.canvas.height * 0.5));
  this.sanitiseview();
};


/**
 * Moves the selected Cell
 *
 */
Map.prototype.moveSelected = function(dx, dy) {
  if (this.selectedCellX + dx > 0)
    this.selectedCellX += dx;
  if (this.selectedCellY + dy > 0)
    this.selectedCellY += dy;
  this.getCell(this.selectedCellX, this.selectedCellY).select();
  alert(this.selectedCellX + ', ' + this.selectedCellY);
};


/**
 * Updates the display of Cells at the current view area
 *
 */
Map.prototype.draw = function(ctx) {
  
  // Apply the panning deltas to the view
  if (this.panx != 0 || this.pany !=0) {
    this.viewx += this.panx;
    this.viewy += this.pany;
    this.sanitiseview();
    ooc.redraw();
  }
  
  ctx.save();
  ctx.clearRect(0, 0, ooc.canvas.width, ooc.canvas.height);
  ctx.translate(-this.viewx, -this.viewy);
  var lf = this.firstcell;
  for (var y = 0; y < this.CELLSPERCOL; y++) {
    for (var i = lf; i < lf + this.CELLSPERROW; i++ )
      this.cells[i].draw(ctx);
    lf += this.width;     
  }
  lf = this.firstcell;
  for (var y = 0; y < this.CELLSPERCOL; y++) {
    for (var i = lf; i < lf + this.CELLSPERROW; i++ )
      for (var o = 0; o < this.cells[i].objects.length; o++)
        this.cells[i].objects[o].draw(ctx);
    lf += this.width;     
  }
  ctx.restore();
  
  
  /* Minimap. This should maybe be a seperate class 
  ctx.save();
  ctx.scale(0.1, 0.1);
  var last = this.cells[this.cells.length - 1];
  var right = last.x + last.width;
  var bottom = last.y + last.height;
  ctx.fillRect(0, 0, right, bottom);
  lf = this.firstcell;
  for (var y = 0; y < this.CELLSPERCOL; y++) {
    for (var i = lf; i < lf + this.CELLSPERROW; i++ )
      this.cells[i].draw(ctx);
    lf += this.width;     
  }
  lf = this.firstcell;
  for (var y = 0; y < this.CELLSPERCOL; y++) {
    for (var i = lf; i < lf + this.CELLSPERROW; i++ )
      for (var o = 0; o < this.cells[i].objects.length; o++)
        this.cells[i].objects[o].draw(ctx);
    lf += this.width;     
  }
  ctx.restore();*/
  
  ctx.drawImage(resource.corner, -5, -4);
  ctx.drawImage(resource.corner, ooc.canvas.width - 5, -4);
  ctx.drawImage(resource.corner, ooc.canvas.width - 5, ooc.canvas.height - 5);
  ctx.drawImage(resource.corner, -4, ooc.canvas.height - 5);
};




/**
 * Creates a hardcoded map for testing Alpha phase.
 *
 */
function createtestmap() {

  // Create a blank 25x25 map
  var map = new Map(25, 25);
  
  
  map.getCell(11, 11).setType(resource.floor);
  map.getCell(12, 11).setType(resource.floor);
  map.getCell(13, 11).setType(resource.floor);
  var cell = map.getCell(12, 12);
  var s = new Summonsing();
  cell.setType(resource.floor);
  s.setLocation(cell);
  map.getCell(11, 12).setType(resource.floor);
  map.getCell(13, 12).setType(resource.floor);
  map.getCell(12, 13).setType(resource.floor);
  
  return map;
};
